﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Red.GameData.Raw
{
    /// <summary>
    /// Data property value holder
    /// Defines a value override for a specific class property
    /// NOTE: each property may hold multiple values
    /// The values from each property in an object dependency stack are merged into a final list by the value resolver
    /// NOTE: we don't know here if the property is an array or not, therefore we are tracking ALL the values
    /// </summary>
    public partial class DataProperty : Red.Core.DataConsistency.ConsistentObject
    {
        /// <summary>
        /// Name of the property (usually there's a matching ReflectionProperty in the class of the object)
        /// There may be cases when there's NO reflection property (mismatched data for example)
        /// </summary>
        public String Name { get; private set; } // set only once

        /// <summary>
        /// Parent data object, can be used to walk the hierarchy up to the whole data collection
        /// </summary>
        public DataObject Parent { get; private set; } // set only once

        /// <summary>
        /// List of values (by value ID) to suppress before adding values from this property
        /// This is used in the value resolver to build final list of values.
        /// Use the Action_SuppressValue, Action_UnsuppressValue methods to modify this list
        /// </summary>
        public List<Guid> SupressedValues { get; private set; }

        /// <summary>
        /// Data values defined at this property
        /// </summary>
        public List<DataValue> Values { get; private set; }

        /// <summary>
        /// Initialize data property holder
        /// </summary>
        /// <param name="parent">Data object that owns this data property</param>
        /// <param name="name">Name of this data property</param>
        internal DataProperty(DataObject parent, String name, bool isFinal, bool clearIncomingValues)
        {
            Name = name;
            Parent = parent;
            SupressedValues = new List<Guid>();
            Values = new List<DataValue>();

            _isFinal = isFinal;
            _clearAllIncomingValues = clearIncomingValues;
        }

        /// <summary>
        /// Toggle clearing of all incoming values for the item thus making it totally prone to the base object's influences
        /// </summary>
        public Boolean ClearAllIncomingValues
        {
            get
            {
                return _clearAllIncomingValues;
            }
            set
            {
                if (value != _clearAllIncomingValues)
                {
                    _clearAllIncomingValues = value;
                    MarkModified();
                }
            }
        }

        /// <summary>
        /// Toggle treating this data property as a final provider of value in this object's tree
        /// </summary>
        public Boolean IsFinal
        {
            get
            {
                return _isFinal;
            }
            set
            {
                if (value != _isFinal)
                {
                    _isFinal = value;
                    MarkModified();
                }
            }
        }

        /// <summary>
        /// Mark this data property as modified
        /// Since we are not tracking modifications at such fine-grain level this will propagate the request to the object
        /// </summary>
        public void MarkModified()
        {
            Debug.Assert(Parent != null);
            Parent.MarkModified();

            // make sure any editor cached values will be updated
            InvalidateConsistencyMarker();
        }

        /// <summary>
        /// Should be remove ALL incoming values ?
        /// This is very good to purge an array without uncontrollable amount of suppressed values
        /// </summary>
        private Boolean _clearAllIncomingValues;

        /// <summary>
        /// Should the values defined at this data property be considered final?
        /// Final values will not be overridden in deriving objects
        /// This is very useful to constrain the possible scope of object changes once you go down the hierarchy
        /// </summary>
        private bool _isFinal;
    }

}
